package gui;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.swing.Box;
import javax.swing.DefaultComboBoxModel;
import javax.swing.DefaultListModel;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTabbedPane;
import javax.swing.JTextArea;
import javax.swing.ListSelectionModel;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.text.BadLocationException;

import model.data.Audio;
import model.data.FileDescription;
import model.data.Status;
import model.data.Wizzer;
import model.data.Interface.UserListObserver;
import model.entity.User;

import controller.ChatController;

import controller.Interface.GuiController;
import gui.interfaces.FromUser;
import gui.interfaces.ToUser;

/**
 * <b>Project ChatSystemG6 INSA 4INFOA1 - 2013/2014</b>
 * <P>
 * <i>Package gui </i> <br>
 * ChatGUI is The main page of the chatSystem <br>
 * it implements the interface ActionListener, UserListObserver, FromUser,
 * ToUser, ListSelectionListener
 * 
 * @author Christelle SIAGO HAPPI
 */
public class ChatGUI extends JFrame implements UserListObserver, FromUser,
		ToUser, ActionListener, ListSelectionListener {

	private static final long serialVersionUID = 1L;

	// the components of the gui
	private GuiController controller;
	private String username;
	private ListSelectionModel listSelectionModel;
	private Boolean bConnected;
	private JScrollPane listScroll;
	private JLabel listTitleLabel;
	private JPanel listPanel;
	private JSplitPane split;
	private JSplitPane split1;
	private JPanel conversationPanel;
	private JList list;
	private DefaultListModel listmodel;
	private JTextArea conversationText;
	private JScrollPane conversationScroll;
	private Boolean isUserSelected;
	private JButton disconnectButton;
	private String localUser;
	private HashMap<String, DiscussionTab> discussionPaned;
	private JMenuBar menuBar;
	protected JTabbedPane multichatArea;
	private String remoteUser;
	private FileDescription fileDescription;
	private JLabel statusBar;
	private DiscussionTab tab;
	private ImagePanel panel;
	private JLabel labelStatus;
	private WelcomePage homePage;
	private DefaultTab defaultTab;
	private Font font;
	private JLabel welcomeLabel;
	private Box b1;
	private Box b2;
	private String mLog;
	private JMenu menuHelp;
	private AboutDialog dialog;
	private JMenuItem closeTabsItem;
	private JComboBox statusBox;
	private TabColor color;
	private ChatPanel panels;
	

	/**
	 * *The constructor
	 * 
	 * @param controller
	 *            : the controller of the chatSystem
	 */
	public ChatGUI(GuiController controller) {

		super();
		this.controller = controller;
		((ChatController) this.controller).setGUI(this);
		this.setSize(new Dimension(700, 500));
		this.setLocationRelativeTo(null);
		discussionPaned = new HashMap<String, DiscussionTab>(5);
		setTitle("ChatSystem Main Page");
		setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
		initComponents();
		this.color = new TabColor(multichatArea);
		panels=new ChatPanel();
		this.setBackground(Color.CYAN);

	}

	/**
	 * 
	 * @return the localUser
	 */
	public String getLocalUser() {
		localUser = controller.getLocalUser();
		// localUser = homePage.getUsername();
		return localUser;
	}

	/**
	 * assign the username to the localUSer
	 * 
	 * @param localUser
	 */
	public void setLocalUser(String localUser) {
		this.localUser = localUser;
		this.controller.setLocalUser(localUser);

	}

	/**
	 * 
	 * @return the remote user
	 */
	public String getRemoteUser() {
		return remoteUser;
	}

	/**
	 * set the status of the local user
	 * 
	 * @param bValue
	 */
	public void setConnected(boolean bValue) {
		this.bConnected = bValue;
	}

	/**
	 * get the status of the local user
	 * 
	 * @return
	 */
	public boolean connected() {
		return bConnected;
	}

	/**
	 * assign the welcomePage to this ChatGUI
	 * 
	 * @param homePage
	 */
	public void setWelcomePage(WelcomePage homePage) {
		this.homePage = homePage;
	}

	/**
	 * init all the components of the frame
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	private void initComponents() {

		font = new Font("Tohoma", Font.ITALIC, 13);
		// setting the icom image of the frame
		setIconImage(new ImageIcon("/ressources/app.gif").getImage());

		statusBar = new JLabel();

		// setting the userList label title
		listTitleLabel = new JLabel("Connected Users List");
		listTitleLabel.setFont(new Font("Tahoma", 0, 14));
		listTitleLabel.setForeground(new Color(0, 153, 204));

		// setting the userList
		listmodel = new DefaultListModel();
		list = new JList(listmodel);
		listSelectionModel = list.getSelectionModel();
		listSelectionModel.addListSelectionListener(this);
		listSelectionModel
				.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);

		list.setPreferredSize(new Dimension(150, 200));
		list.setToolTipText("Users List");
		// list.setCellRenderer(new ContactListCellRender());

		// putting a scroll to the list
		listScroll = new JScrollPane(list);

		// setting the disconnection button
		disconnectButton = new JButton("disconnect");
		disconnectButton.addActionListener(this);

		// setting the welcome message
		welcomeLabel = new JLabel("Welcome  !!" /*+ this.controller.getLocalUser()*/);
		welcomeLabel.setFont(font);
		welcomeLabel.setForeground(new Color(0, 153, 204));

		
		labelStatus = new JLabel();
		labelStatus.setFont(font);
		labelStatus.setText("online");
		labelStatus.setIcon(new ImageIcon(getClass().getResource(
				"/ressources/online.gif")));
		labelStatus.setForeground(new Color(0, 153, 204));
		
		

		// setting the combox box status
		statusBox = new JComboBox();
		statusBox.setMinimumSize(new Dimension(50,20));
		statusBox.setMaximumSize(new Dimension(100,20));
		statusBox.setPreferredSize(new Dimension (50,20));
		statusBox.setModel(new DefaultComboBoxModel(new String[] { "Online",
				"Absent" }));
		statusBox.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent evt) {
				statusBoxActionPerformed(evt);
			}
		});

		// adding a menu to the frame
		menuBar = new JMenuBar();
		menuBar.setForeground(new java.awt.Color(0, 102, 255));
        menuBar.setFont(new java.awt.Font("Cambria", 0, 14));
		menuHelp = new JMenu("HELP");
		// menucomponent.add("About");
		// menucomponent.add(disconnectButton);

		menuHelp.add("About");
		menuHelp.setFont(new Font("Tahoma", 0, 14));
		menuHelp.addMouseListener(new MouseAdapter() {
			public void mouseClicked(MouseEvent evt) {
				menuHelpMouseClicked(evt);
			}

		});
		

		JMenu disconnectComponent = new JMenu("MENU");
		JMenuItem disconnectItem = new JMenuItem();
		closeTabsItem = new JMenuItem();
		closeTabsItem.setText("closeTabs");
		closeTabsItem.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent evt) {
				closeTabsItemActionPerformed(evt);
			}
		});
		disconnectComponent.add(closeTabsItem);
		//disconnectComponent.add("close all tabs");

		disconnectItem.setText("disconnect");
		disconnectItem.addActionListener(new ActionListener() {

			public void actionPerformed(ActionEvent arg0) {
				disconnectItemActionPerformed(arg0);

			}
		});

		disconnectComponent.add(disconnectItem);
		menuBar.add(disconnectComponent);
		menuBar.add(menuHelp);

		// setting the chatRoom area paned
		multichatArea = new JTabbedPane();
		multichatArea.addTab("Default", defaultPage());
		JLabel lab = new JLabel("Statut ");
		//lab.setIcon(new ImageIcon(getClass().getResource(
				//	"src/ressources/app.png")));

		/*
		 * positioning the components
		 */
		b1 = Box.createVerticalBox();
		b1.add(welcomeLabel);
		// b1.add(listTitleLabel);

		b2 = Box.createHorizontalBox();
		b2.add(lab);
		b2.add(labelStatus);
		b2.add(Box.createHorizontalStrut(5));
		b2.add(statusBox);
		//b2.add(Box.createHorizontalStrut(5));

		Box b3 = Box.createVerticalBox();
		b3.add(b1);
		b3.add(b2);
		//b3.add(Box.createGlue());
		b3.add(listTitleLabel);
		b3.add(listScroll);

		this.add(menuBar, BorderLayout.NORTH);
		// this.add(b1, BorderLayout.WEST);
		// this.add(listScroll, BorderLayout.CENTER);
		// this.add(multichatArea, BorderLayout.EAST);

		this.add(
				new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, b3, multichatArea),
				BorderLayout.CENTER);

		// this.add(new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, this.listScroll,
		// multichatArea), BorderLayout.CENTER);

		Container c = getContentPane();
		// insertion of the background image
		//panel = new ImagePanel(
			//	new ImageIcon("src/gui/images/test2.jpg").getImage());
		//panel.setLayout(null);


		this.setVisible(true);
	}

	/**
	 * called when the local user want to connect to the ChatSystem
	 */
	@Override
	public void connect() {
		this.setLocalUser(this.homePage.getUsername());
		username = controller.getLocalUser();
		controller.performConnect(username);
		this.bConnected = true;
		Audio audio = new Audio("connect.wav");
		this.displayWelcomePage(false);
		System.out.println("localUser = " + username);

	}

	/**
	 * called when the local user want to disconnect to the ChatSystem
	 */
	@Override
	public void disconnect() {
		this.setVisible(false);
		panels.clear();
        list.setListData(panels.getListPanels());
		this.color.stopActivity();
		this.closeAllDiscussion();
		this.displayWelcomePage(true);
		bConnected = false;
		controller.performDisonnect(this.controller.getLocalUser());
		this.homePage.setUsernameArea("");
	}

	/**
	 * @param isDisplay
	 *            is true when the local user is disconnected and false
	 *            otherwise
	 */
	@Override
	public void displayWelcomePage(boolean isDisplay) {
		this.homePage.setVisible(isDisplay);

	}

	/**
	 * called when the local user want to send a text message to a remote user
	 */
	@Override
	public void sendMessage(String local, String remote, String text) {

		controller.performMessage(local, remote, text);
	}

	/**
	 * indicates if a remote user is selected
	 */
	@Override
	public boolean selectUser(boolean isUserSelected) {
		this.isUserSelected = isUserSelected;
		return isUserSelected;

	}

	/**
	 * open a new discussion
	 * 
	 * @param c
	 *            : the remote user
	 */
	@Override
	public void openNewDiscussion(String c) {
		if (!discussionPaned.containsKey(c))
			// SwingUtilities.invokeLater(new OpenNewDiscussion(c));
			SwingUtilities
					.invokeLater(new NewDiscussion(c, this, multichatArea));
	}

	/**
	 * close all the discussion tab
	 */
	@Override
	public void closeAllDiscussion() {
		multichatArea.removeAll();
		multichatArea.addTab("Default", defaultPage());
		discussionPaned.clear();
	}

	/**
	 * called when the local user receive a message from the remote user
	 * @throws BadLocationException 
	 */
	@Override
	public void receivedMessage(String remote, String text) throws BadLocationException {
		DiscussionTab tab = discussionPaned.get(remote);
		multichatArea.setBackgroundAt(0, Color.ORANGE);
		tab.setBackground(Color.ORANGE);
		tab.receivedMessage(text);
		addLog(remote +" sent you a new message");
		defaultTab.setNotification(displayLog());

	}

	/**
	 * called when the local user want to send a file
	 */
	public void sendFileRequest(FileDescription file, String username) {
		this.controller.performFileRequest(file, username);

	}

	/**
	 * action performed when the disconnection button is pressed
	 */
	@Override
	public void actionPerformed(ActionEvent arg0) {

		disconnect();
		this.setVisible(false);
		this.displayWelcomePage(true);

	}

	/**
	 * action performed when the local user want to start a discussion
	 */
	@Override
	public void valueChanged(ListSelectionEvent arg0) {
		if (arg0.getValueIsAdjusting() == false) {

			// If no contact is selected, it disables the button
			// Send message and file
			if (list.getSelectedIndex() == -1) {
				selectUser(false);

			} else {

				selectUser(true);

				String remoteUser = (String) list.getSelectedValue();
				sendWizz(remoteUser);
				System.out.println("remoteUser : " + remoteUser);
				openNewDiscussion(remoteUser);
				this.color.startActivity();
			}
		}

	}

	/**
	 * add a new user in the userList
	 */
	@SuppressWarnings("unchecked")
	@Override
	public void addElement(User user) {
		  listmodel.addElement(user.getUsername());
          addLog(user.getUsername() + " is now connected \n");

          defaultTab.setNotification(displayLog());
		/**listmodel.addElement(user.getUsername());
		System.out.println("user added");
			 panels.insertOnlinePanel(user.getUsername());
			 System.out.println("user added : pannel added");
			//list.setListData(panels.getListPanels());
			if(!listmodel.contains(user.getUsername())){
		}**/
		

		

	}

	/**
	 * remote a user in the list
	 */
	@Override
	public void removeElement(User user) {
	    listmodel.removeElement(user.getUsername());
        discussionPaned.remove(user.getUsername());
        addLog(user.getUsername() + " is now disconnected \n");
        defaultTab.setNotification(displayLog());
	

	}

	/**
	 * 
	 * @return the default tab
	 */
	private JPanel defaultPage() {
		defaultTab = new DefaultTab();
		return defaultTab;
	}

	/**
	 * create a new tab in the ChatRoom area
	 * 
	 * @param c
	 *            : the remote user
	 * @return the default tab
	 * @throws IOException 
	 */

	public JPanel createPage(String c) throws IOException {
		tab = new DiscussionTab(c, multichatArea);
		tab.setLocalUser(localUser);
		tab.setRemoteUser(c);
		tab.setGui(this);

		discussionPaned.put(c, tab);

		return tab;
	}

	/**
	 * Refresh the state of the transfer in the System Tray
	 */
	@Override
	public void refreshFileTransferSate(boolean isAccept) {
		if (isAccept) {
			String message = "Accepted request, Uploading. . .\n";
			this.refreshFileTransferStatus(message);
		} else {
			String message = "Request rejected, canceled Transfer !!\n";
			System.out.println(message);
			this.refreshFileTransferStatus(message);
		}
	}

	/**
	 * Displays the status of a file transfer
	 * 
	 * @param sMsg
	 *            Transfer information received
	 */
	public void refreshFileTransferStatus(String sMsg) {
		addLog(sMsg);
		defaultTab.setNotification(displayLog());
		tab.setNotification(sMsg);
	}

	/**
	 * called when the remote user accept or not the file request
	 * 
	 * @param sFilename
	 * @param rUser
	 * @return the response of the remote user to the file request
	 */
	@Override
	public boolean responseToFileRequest(FileDescription sFilename, String rUser) {
		String sToDisplay = rUser + " want to transfer the file"
				+ sFilename.getName();
		String sTitle = "File Transfer";

		addLog(sToDisplay);
		defaultTab.setNotification(displayLog());

		Audio audio = new Audio("asker.wav");
		int isOK = JOptionPane.showConfirmDialog(discussionPaned.get(rUser),
				sToDisplay, sTitle, JOptionPane.YES_NO_OPTION,
				JOptionPane.QUESTION_MESSAGE);

		boolean bAccept = (isOK == JOptionPane.OK_OPTION) ? true : false;

		return (bAccept);

	}

	/**
	 * called when a remote user sent a wizz message
	 */
	@Override
	public void receiveWizz(String remoteUsername) {

		

		Wizzer wizzer = new Wizzer(this);
		
		//Audio wizz = new Audio("/ressources/wizzMsn.wav");
		addLog(remoteUsername + " sent you a wizz\n");
		tab.setNotification(remoteUsername + "sent you a wizz");
		defaultTab.setNotification(displayLog());
	}

	/**
	 * called when the localuser want to change his status
	 * 
	 * @param status
	 */
	public void sendStatus(String status) {
		controller.performStatus(status);
	}

	/**
	 * 
	 * Notification de presence
	 * 
	 * @param remoteUsername
	 *            Login de l'utilisateur distant
	 * @param status
	 *            Status de l'utilisateur local
	 */

	@Override
	public void receivedStatus(String remoteUsername, String status) {
		/* panels.deletePanel(remoteUsername);
	        if(status.equals((Status.AWAY).toString())){
	            panels.insertAwayPanel(remoteUsername);
	        }else if(status.equals((Status.CHAT).toString())){
	            panels.insertOnlinePanel(remoteUsername);
	        }
	       // list.setListData(panels.getListPanels());
	        * 
	        */
		addLog(remoteUsername + " changed his status. He is now " + status);
		defaultTab.setNotification(displayLog());
	}

	/**
	 * @throws BadLocationException 
	 * 
	 */
	@Override
	public void receivedUserNotification(String remoteUsername,
			boolean isWriting) throws BadLocationException {
		DiscussionTab tab = discussionPaned.get(remoteUsername);
		tab.setNotification(remoteUsername + " is writing a new message");
		if(isWriting)
			tab.insertComposing(remoteUsername);
		else
			tab.deleteComposing(remoteUsername);
	}

	/**
	 * 
	 */
	@Override
	public void sendWizz(String remoteUser) {
		this.controller.performSendWizz(remoteUser);

	}

	/**
	 * display a welcome message
	 */
	public void setWelcome() {
		welcomeLabel.setText("\nWelcome " + username + " ! \n");
		;
	}

	/**
	 * 
	 */
	@Override
	public void remoteIsWriting(String rUserName, boolean isWriting) {
		this.controller.performRemoteIsWriting(rUserName, isWriting);

	}

	/**
	 * get the conversation historic
	 * 
	 * @param log
	 *            Login provided by the local user
	 */
	private void addLog(String log) {
		Date d = new Date();
		DateFormat dateFormat = new SimpleDateFormat("dd/MM/yy HH'h'mm");
		mLog += "[" + dateFormat.format(d) + "] " + log + "\n";

	}

	/**
	 * displays the conversation historic
	 * 
	 * @return the conversation historic
	 */
	private String displayLog() {
		return mLog;
	}

	/**
	 * display the menu help
	 * @param evt
	 */
	private void menuHelpMouseClicked(MouseEvent evt) {
		String appName = "ChatSystemG6 4INFO INSA\n";
		String appVersion = "1.0";
		String appBuild = "December 2013";

		dialog = new AboutDialog(this, appName, appVersion, appBuild);
		dialog.setVisible(true);

	}

	/**
	 * called when the local user want to close all the discussion
	 * @param evt
	 */
	public void closeTabsItemActionPerformed(ActionEvent evt) {
		this.closeAllDiscussion();

	}

	/**
	 * called when the user want to be disconnected
	 * @param arg0
	 */
	private void disconnectItemActionPerformed(ActionEvent arg0) {
		System.out.println(" action perform disconnect");
		if (this.bConnected) {

			int isOK = JOptionPane.showConfirmDialog(this,
					"Are you sure to quit the ChatSystem", "Disconnection",
					JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);

			boolean response = (isOK == JOptionPane.OK_OPTION) ? true : false;

			if (response) {
				this.disconnect();
			} else {
				addLog(" action perform disconnect >> failed");
				defaultTab.setNotification(displayLog());
				JOptionPane.showMessageDialog(this, "you have to connect",
						"impossible to get disconnected",
						JOptionPane.ERROR_MESSAGE);
			}
		}
	}
/**
 * called when the user want to change his status
 * @param evt
 */
	private void statusBoxActionPerformed(ActionEvent evt) {
		try {

			String myStatus = statusBox.getSelectedItem().toString();
			labelStatus.setText(myStatus);

			if (myStatus.equals("Online")) {
				labelStatus.setIcon(new ImageIcon(getClass().getResource(
						"/ressources/online.gif")));
			}
			if (myStatus.equals("Absent")) {
				labelStatus.setIcon(new ImageIcon(getClass().getResource(
						"/ressources/away.png")));
			}
			this.sendStatus(myStatus);
		} catch (Exception ex) {
			Logger.getLogger(ChatGUI.class.getName()).log(Level.SEVERE, null,
					ex);
			JOptionPane.showMessageDialog(this,
					"Impossible to change the status", "Error",
					JOptionPane.ERROR_MESSAGE);

		}
	}
}
